# Python ≥3.5 is required
import sys
assert sys.version_info >= (3, 5)
# Scikit-Learn ≥0.20 is required
import sklearn
assert sklearn.__version__ >= "0.20"
# Common imports
import numpy as np
import os
#imports pandas
import pandas as ps
from IPython.display import Image
import os
#import warnings and Repress Warnings
import warnings
warnings.filterwarnings("ignore", message="numpy.dtype size changed")
warnings.filterwarnings("ignore", message="numpy.ufunc size changed")
warnings.filterwarnings("ignore", message="numpy.ndarray size changed")
warnings.filterwarnings('ignore')
# to make this notebook's output stable across runs
np.random.seed(42)
# To plot pretty figures
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="whitegrid") #White Grid
mpl.rc('axes', labelsize=14)
mpl.rc('xtick', labelsize=12)
mpl.rc('ytick', labelsize=12)
# Where to save the figures
PROJECT_ROOT_DIR = "."
CHAPTER_ID= "ProgettoMetascoreVideogames"
IMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, "images")
os.makedirs(IMAGES_PATH, exist_ok=True)
def save_fig(fig_id, tight_layout=True, fig_extension="png", resolution=400):
path = os.path.join(IMAGES_PATH, fig_id + "." + fig_extension)
print("Saving figure", fig_id)
if tight_layout:
plt.tight_layout()
plt.savefig(path, format=fig_extension, dpi=resolution)
def save_figure(figure, fig_id, tight_layout=False, fig_extension="png", resolution=400):
path = os.path.join(IMAGES_PATH, fig_id + "." + fig_extension)
print("Saving figure", fig_id)
if tight_layout:
plt.tight_layout()
figure.savefig(path, format=fig_extension, dpi=resolution)
# Ignore useless warnings (see SciPy issue #5998)
import warnings
warnings.filterwarnings(action="ignore", message="^internal gelsd")
import warnings
warnings.filterwarnings('ignore')
# Hrule--> "====="
hrule = lambda x : "="*x
Hrule = lambda x,y: "="*(x//2)+y+"="*(x//2)
#Funzioni che possono tornarmi utili nel proseguo
def take_most_n(n,column):
return column.value_counts().head(n).index.tolist()
def change_value_to_other(column,top_value,inplace=False):
if(inplace==True):
column.where(column.isin(top_value),other='Other',inplace=True)
else:
column.where(column.isin(top_value),other='Other',inplace=False)
Image(filename=os.path.join(IMAGES_PATH, 'cover.jpg'))
Il mercato videoludico fa parte del più ampio settore dell'intrattenimento, tale particolare "fetta" ha avuto una crescita esponenziale nell'ultimo decennio e si stima che nel corso di quest' anno possa raggiungere un valore complessivo di oltre 160 miliardi di dollari. Intimamente legato a tale ambito è anche il fenomeno degli e-Sport, o "Sport Elettronici", in cui atleti sotto contratto con team professionistici si sfidano in tornei competitivi in diversi giochi e su diverse piattaforme (PC o console).
La mia analisi prende come riferimento un dataset contenente una lista di videogame pubblicati a partire dal 1995 fino al termine del 2018 e cerca di risolvere un problema di regressione in cui ci si concentra sulla previsione del valore di metascore di un gioco, in seguito si daranno informazioni più dettagliate sul significato di tale metrica.
In questa prima parte provvedo a caricare il dataset, visualizzandone alcuni record, per poi procedere a descrivere il significato delle singole colonne.
ds = ps.read_csv(os.path.join(PROJECT_ROOT_DIR, "data","game.csv"))
ds.head(5)
Procedo ad una descrizione dettagliata degli attributi del data set in questione:
Si procede ora ad analizzare più nello specifico le caratteristiche del dataset andando ad effettuare delle operazioni preliminari di pulizia che ci permetteranno nel proseguo una migliore visualizzazione dei dati in questione.
ds.info()
Come si può ben vedere dal risultato del precedente comando info() il dataset contiene un totale di 18 colonne e 20422 record, tra queste colonne 7 sono di tipo intero e rappresentano i valori numerici delle recensioni effettuate dalla critica e dagli utenti incluso l'attributo principale metascore , mentre le restanti 11 sono object (prevalentemente stringhe). Si può notare come lo user_score fa parte delle colonne di tipo object per via della presenza di valori 'tbd' ('to be defined").
ds.shape
Si procede come prima cosa alla rimozione di eventuiali duplicati all'interno dei nostri dati, si deve però preventivamente motivare la scelta effettuata per tale rimozione.
mask=ds.duplicated(subset='name')
name_duplicate=ds[mask]
name_duplicate.head(6)[2:]
Le operazioni effettuate precedentemente mi hanno permesso di selezionare i record che presentano lo stesso nome e che quindi costituiscono lo stesso titolo, nel mondo videoludico è molto frequente che un videogioco venga proposto su diverse piattaforme hardware e inoltre, come si può notare per l'esempio di cui sopra, il metascore del titolo può variare (sensibilmente o meno) in base alla piattaforma per cui è sviluppato. Questo, oltre a sottintendere un certo livello di importanza dell'attributo "platform" nella nostra analisi, giustifica la scelta di non andare ad eliminare record basandomi solo sull'attributo "name".
ds.drop_duplicates(keep='first',inplace=True)
ds.shape
Come si può vedere erano presenti solo 2 elementi duplicati che abbiamo rimosso dal dataset. Si possono a questo punto preliminarmente rimuovere le colonne "name" e "link" dato che non sono significative ai fini della nostra analisi.
ds.drop(columns=['name','link'], inplace = True)
ds.shape
Le colonne rimanenti sono perciò le seguenti:
ds.columns
Si procede ora a gestire la presenza di eventuali valori nulli nel dataset, prima di fare ciò è però necessario andare a sostituire il valore "tbd" di user_score in NaN in modo da avere una visione più chiare di tutti i valori nulli presenti e inoltre permettendoci di rendere tale colonna di tipo float.
ds['user_score']=ds['user_score'].replace('tbd',np.nan)
ds['user_score']=ds['user_score'].astype('float64')
ds.info()
Andiamo ora a vedere la percentuale effettiva di valori nulli presenti nel dataset per ogni colonna
ps.DataFrame({'null%':ds.isnull().sum()/ds.shape[0],
'null_num':ds.isnull().sum()})
Si possono notare diverse colonne con valori nulli, si procede in seguito alla trattazione delle singole colonne e ad eventuali operazioni di conversione.
Data la presenza di pochi valori nulli, solo 37 che sono molto meno dell'1%, si decide di eliminare i record a cui questi fanno riferimento.
ds.drop(index=ds[ds['developer'].isna()].index, inplace=True)
print("Valori nulli restanti nella colonna 'developer':",ds.developer.isnull().sum())
Come per la colonna precedente anche in questo caso avendo pochissimi valori nulli si è deciso di eliminare i record associati.
ds.drop(index=ds[ds['publisher'].isna()].index, inplace=True)
print("Valori nulli restanti nella colonna 'publisher':",ds.publisher.isnull().sum())
Questa colonna contiene oltre 7000 valori nulli che rappresentano il 35% del totale dei valori, data la numerosità di questi si è deciso di andarli a soltituire con la costante "1 or more" poichè comunque sicuramente qualsiasi videogame deve poter permettere ad almeno un giocatore di poter appunto giocare, ma non abbiamo informazioni necessarie per poter stabilire se tali titoli sono single player o meno; inoltre questa scelta, al posto di inserire unicamente "1 Player", ci evita di accorpare record di cui non conosciamo il numero esatto di giocatori con record per i quali si ha solamente un singolo giocatore. A tale scopo si va ad impiegare un oggetto SimpleImputer con strategia 'constant'.
try:
from sklearn.impute import SimpleImputer # Scikit-Learn 0.20+
except ImportError:
from sklearn.preprocessing import Imputer as SimpleImputer
imputer_players = SimpleImputer(strategy='constant',fill_value="1 or more",missing_values=np.nan, verbose=0,copy=False)
Pur avendo relativamente pochi valori nulli in tale colonna si possono con semplicità sostituire con il valore costante RP ossia Rate Pending che, come detto in precedenza, viene impiegato quando appunto non è stato ancora definito il contenuto di un generico videogioco a quale fascia d'età appartiene; per fare ciò si andrà ad impiegare un oggetto SimpleImputer con strategia 'constant', inoltre si provvede a sostituire il valore K-A con E sempre per quanto detto precedentemente nella descrizione degli attributi.
imputer_rating = SimpleImputer(strategy='constant',fill_value="RP",missing_values=np.nan, verbose=0,copy=False)
ds['rating'].replace({"K-A":"E"},inplace=True)
ds.rating.unique()
Siccome quasi tutti i valori di tale colonna sono nulli (più del 98%) non è possibile stabilire una strategia sostitutiva valida perciò si procede con l'eliminazione di tale colonna
ds.drop(columns=['attribute'], inplace = True)
print("Colonne rimanenti:\n",ds.columns)
Per quanto riguarda tale colonna non è presente alcun "NaN", tuttavia si è deciso di andare ad impiegare unicamente l'anno di pubblicazione del titolo invece della data completa perchè non vi è un'importanza così marcata per la valutazione di un gioco nella conoscenza del suo mese o giorno di pubblicazione, quanto invece può esserci nel sapere l'anno di pubblicazione; inoltre si provvede anche alla conversione della colonna come tipo intero (data la presenza solo dell'anno)
ds['release_date']=ps.to_datetime(ds['release_date'])
ds['release_date']=ds['release_date'].dt.year
ds.rename(columns={"release_date":"year"},inplace=True)
ds.year.unique()
Data la presunta importanza di tale attributo ai fini della previsione e la limitata presenza di valori nulli, che occupano infatti solo il 12% de totale (2595), si procede alla rimozione dei record associati a questi.
ds.drop(index=ds[ds['user_score'].isna()].index, inplace=True)
print("Valori nulli restanti nella colonna 'user_score':",ds.publisher.isnull().sum())
Andiamo ora ad applicare gli oggetti SimpleImputer precedentemente definiti:
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
pipe_players=Pipeline([
("imputer_players",imputer_players)
])
pipe_rating=Pipeline([
("imputer_rating",imputer_rating)
])
pipeline_imputer = ColumnTransformer([
("pipe_players",pipe_players,['players']),
("pipe_rating",pipe_rating,['rating'])
])
ds1 = pipeline_imputer.fit_transform(ds)
Andiamo ora a mappare le colonne ottenute dalla trasformazione tramite imputer e le restanti colonne che non hanno subito alcuna trasformazione in un dataset.
game=ps.DataFrame({
"platform":ds.platform,
"developer":ds.developer,
"publisher":ds.publisher,
"genre(s)":ds["genre(s)"],
"players":ds1[:,0],
"rating":ds1[:,1],
"year":ds.year,
"critic_positive":ds["critic_positive"],
"critic_neutral":ds["critic_neutral"],
"critic_negative":ds["critic_negative"],
"metascore":ds.metascore,
"user_positive":ds["user_positive"],
"user_neutral":ds["user_neutral"],
"user_negative":ds["user_negative"],
"user_score":ds["user_score"]
})
#game.to_csv(os.path.join(PROJECT_ROOT_DIR, "data","game_clean.csv"))
game.head(5)
A questo punto il dataset è stato ripuliuto da tutti gli eventuali valori mancanti, come si può appunto constatare dal comando sottostante.
ps.DataFrame({'null%':game.isnull().sum()/game.shape[0],
'null_num':game.isnull().sum()})
Avendo quindi ripulito i dati si possono andare a presentare delle statistiche generali sulle colonne che presentano valore numerico mediante l'utilizzo del comando describe().
game.describe()
Dopo aver effettuato una pima serie di operazione di pulizia dei nostri dati concentriamoci ora sulla loro visualizzazione per cercare di individuare i fattori che concorrono al valore di metascore di un videogioco.
Come prima cosa andiamo a mostrare la distribuzione dei valori di metascore nel nostro dataset, si può osservare che occorrono con maggior frequenza i valori compresi tra 70-80. Infatti in seguito si è provveduto a graficare anche l'istogramma relativo al numero di rercord che hanno uno specifico valore di metascore impiegando 20 intervalli.
plt.figure(figsize=(15,10))
p = sns.kdeplot(game.metascore, shade=True, color='blue')
plt.grid()
plt.xlabel('Metascore')
plt.ylabel('Frequency')
plt.title("Metascore Distribution", size=20)
#save_fig("metascore_dist")
plt.show()
plt.figure(figsize=(15,10))
game['metascore'].hist(bins=20)
plt.xlabel('Metascore')
plt.ylabel('count')
plt.title("Metascore values", size=20)
#save_fig("metascore_hist")
plt.show()
Andiamo ora ad analizzare se vi possono essere delle relazioni tra l'attributo year e l'attributo principale metascore: una prima occhiata al grafico sottostante potrebbe indurci a pensare che effettivamente nel corso del tempo la valutazione di un videogioco da parte della critica vada mediamente a diminuire.
plt.figure(figsize=(15,10))
p = sns.lineplot(x = 'year', y = 'metascore', data = game, color='red')
plt.title("metascore changes during years", size =20)
#save_fig("metascore_years_line")
plt.show()
mean_metascore_per_year = game.groupby('year')['metascore'].mean()
plt.figure(figsize=(15,10))
p = sns.barplot(x = mean_metascore_per_year.index, y = mean_metascore_per_year.values)
p = plt.xticks(rotation=90)
plt.title("Mean metascore per year", size=20)
plt.ylabel("mean")
#save_fig("metascore_years_mean")
plt.show()
In realtà andando più a fondo si può dare una spiegazione a questo fenomeno vedendo la numerosità di record campionati prima dell'anno 2000:
game.plot(kind = "scatter", x = "year", y = "metascore" ,color = "r", figsize=(15,10))
plt.xlabel("year")
plt.ylabel("metascore")
plt.title("plotting (year, metascore)", size =20)
#save_fig("metascore_years_scatter")
plt.show()
Si può giustificare lo strano comportamento della curva presa in analisi precedentemente guardando il grafico di cui sopra, il numero di videogiochi presenti nel dataset facenti parte del periodo 1995-1999 è nettamente inferiore rispetto agli anni successivi al 2000 (compreso), perciò tale bassa numerosità ha contribuito a valori medi di metascore molto più elevati per i videogiochi rilasciati in tale periodo. Per il resto non sembrano esserci relazioni rilevanti, come era giusto aspettarsi, tra l'attributo year e l'attributo metascore.
Passiamo ora alla trattazione dell'attributo rating, si può notare dal grafico sottostante che 5 di 7 etichette hanno comportamenti per quanto riguarda la distribuzione dei valori di metascore abbastanza normali se non simili, confermano per l'appunto quanto già visto precedentemente ossia che il range di valori tra 70-80 sono quelli più frequenti. Per quanto riguarda i record con etichette di rating "AO" e "EC" è necessario andare ad analizzare le cause di tali strane figure.
plt.figure(figsize=(15,10))
p = sns.violinplot(x = 'rating', y = 'metascore', data = game)
plt.title("metascore distribution per rating", size=20)
#save_fig("rating_violin")
plt.show()
plt.figure(figsize=(15,10))
p = sns.countplot(x = game.rating)
p = plt.xticks(rotation=90)
plt.title("number of records per rating value", size=20)
#save_fig("rating_count")
plt.show()
print("Record per l'etichetta di rating 'EC':")
game.loc[game.rating=='EC']
print("Record per l'etichetta di rating 'AO':")
game.loc[game.rating=='AO']
La causa delle anomalie nel "violinplot" precedente, come si poteva immaginare, sono dovute alla bassa numerosità di record che rappresentano videogiochi etichettati come "EC" oppure "AO" nel nostro dataset, rispettivamente 1 e 2 soli record, mentre si decide di non andare a modificare gli elementi appartenenti alla categoria di rating "AO", uno studio più approfondito del contesto mi porta alla scelta di accorpare il singolo elemento etichettato "EC" con i restanti record di rating "E"; questo perche effettivamente risulta essere una categoria passata in disuso nel tempo.
game['rating']=game['rating'].replace('EC','E')
#game.to_csv(os.path.join(PROJECT_ROOT_DIR, "data","game_clean.csv"))
print("Numero di record con etichetta di rating 'EC': ",(game.rating=='EC').sum())
print("Numero di record con etichetta di rating 'AO': ",(game.rating=='AO').sum())
Si prosegue effettuando la visualizzazione dei generi di videogame, in particolare si va a graficare tramite istogramma il numero di titoli che fanno parte di ogni genere:
plt.figure(figsize=(15,10))
p = sns.countplot(x = 'genre(s)', data = game)
p = plt.xticks(rotation=90)
plt.title("number of games per genre(s)", size=20)
#save_fig("genre_count")
plt.show()
Si può notare come videogiochi di genere Action siano quelli maggiormente presenti nel nostro dataset, inoltre escludendo insieme a questo altri 6 generi che riescono a raggiungere, o superare, la soglia dei 1000 titoli, gli altri sono presenti solo in minima quantità. In particolare si osserva il genere Other:
print("Numero di record con genere 'Other': ",(game['genre(s)']=='Other').sum())
Data la presenza di un solo titolo, per eventuali trasformazioni future applicabili al dataset nella fase di preparazione per gli algoritmi di analisi, si sceglie di conservare tale record. Inoltre dal grafico sottostante non si evince una dominanza particolare di valori elevati di metascore per determinate tipologie di generi videoludici, tralasciando 5 generi che superano la soglia di 80 gli atri si assestano nella maggior parte dei casi nel range 60-70; ciò che si può invece notare è come per molti di questi viene campionato il valore medio con la stima dell'errore che si compie mentre per altri l'errore risulta nullo. Anche questo fenomeno quasi sicuramente sarà dovuto alla bassa numerosità di elementi per queste categorie che potrebbero essere proprio 1 (come per Other), oppure alla presenza di record per la stessa categoria con il medesimo valore di metascore. Inoltre è probabile che l'elevata numerosità di determinate tipologie di generi videoludici vada ad influire negativamente sul metascore medio, come si può osservare ad esempio per il genere Action.
plt.figure(figsize=(15,10))
p = sns.barplot(x = 'genre(s)', y = 'metascore', data = game)
p = plt.xticks(rotation=90)
plt.title("metascore based on genre", size=20)
#save_fig("metascore_genre_barplot")
plt.show()
Indagando più nello specifico risulta vera la prima affermazione, in effetti effettuando un controllo delle colonne del grafico di cui sopra e dei valori di genre(s) sottostanti, che per l'appunto hanno un solo record, si riesce a vedere come l'errore è nullo proprio in corrispondeza di questi.
s=(game['genre(s)'].value_counts()==1)
index = s.index
for genre in index[s]:
print("Numero di record con genere '",genre,"': ",(game['genre(s)']==genre).sum())
Analizziamo ora cosa varia se si decidono di accorpare in Other tutti i generi che presentano pochi valori mantenedo i 10 più numerosi
game2=game.copy()
most_n_genre = take_most_n(10,game2['genre(s)'])
change_value_to_other(game2['genre(s)'],most_n_genre,inplace=True)
fig, ax = plt.subplots(figsize=(20, 15), subplot_kw=dict(aspect="equal"))
def func(pct, allvals):
absolute = int(pct/100.*np.sum(allvals))
return "{:.1f}%\n({:d})".format(pct, absolute)
genres = game2['genre(s)'].value_counts().index.tolist()
data = game2['genre(s)'].value_counts().values.tolist()
data2 = [float(x) for x in data]
wedges, texts, autotexts = ax.pie(game2['genre(s)'].value_counts(), autopct=lambda pct: func(pct, data2), shadow=True)
ax.legend(wedges, genres,
title="genres",
loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
plt.setp(autotexts, size=13, weight="bold")
ax.set_title("top genres pie chart",size=20)
#save_fig("pie_chart_genre")
plt.show()
plt.figure(figsize=(15,10))
p = sns.barplot(x = 'genre(s)', y = 'metascore',data=game2)
p = plt.xticks(rotation=90)
plt.title("mean metascore per genre", size=20)
#save_fig("mean_metascore_genre")
plt.show()
Si nota come il 4.6% di record, ossia un totale di 817, siano stati inseriti nel genere Other andando così ad accorpare circa 55 generi differenti, per l'appunto si può vedere come tale accorpamento sia andato a far diminuire il valore di metascore medio per Other rispetto al valore precedentemente osservato che si attestava intorno a 94
plt.figure(figsize=(15,10))
p = sns.stripplot(x = 'platform',y='metascore',data=game)
plt.title("platforms titles metascore", size=20)
#save_fig("stripplot_platform")
plt.show()
plt.figure(figsize=(15,10))
p = sns.barplot(x = 'platform', y = 'metascore', data = game)
plt.title("metascore based on platform", size=20)
#save_fig("metascore_platform_barplot")
plt.show()
Per quanto riguarda invece la piattaforma hardware per cui vengono sviluppati i diversi videogiochi si può notare una distribuzione abbastanza simile dei valori di metascore, con buona confidenza possiamo affermare che non sarà un attributo preponderante nella valutazione di un gioco, infatti è logico supporre che il metro di giudizio della critica o del generico player non sia condizionato dallo strumento di gioco ma bensì cambi al variare di questo, non sarebbe equo andare ad assegnare valutazioni più elevate a titoli sviluppati per hardware più recenti e quindi con migliori capacità dal punto di vista di elaborazione grafica e performance. Si considera inoltre il fatto che le valutazioni dei diversi titoli siano state fatte in concomitanza con la loro uscita sul mercato, per questo motivo la bontà o meno di un videogame sviluppato per console "vecchie" non pregiudica quella di videogame sviluppati per hardware "nuovi".
Si prosegue l'analisi andando a prendere in considerazione l'attributo publisher che rappresenta la "casa produttrice" del videogame. Si osserva un elevato numero di valori assunti da tale colonna:
print("Numero di publisher: ",len(list(game['publisher'].unique())))
Si procede perciò, come precedentemente per l'attributo genres, all'aggregazione di tali valori mantenendo i più presenti all'interno del dataset.
game3=game.copy()
top_publisher=100
most_n_publisher = take_most_n(top_publisher,game3['publisher'])
change_value_to_other(game3['publisher'],most_n_publisher,inplace=True)
plt.figure(figsize=(15,10))
p = sns.countplot(x = game3.publisher)
p = plt.xticks(rotation=90)
plt.title("number of games for "+str(top_publisher)+" top publisher", size=20)
#save_fig("top_publisher_count")
plt.show()
plt.figure(figsize=(15,10))
p = sns.barplot(x = game3.publisher, y=game3.metascore)
p = plt.xticks(rotation=90)
plt.title("mean metascore for "+str(top_publisher)+" top publisher", size=20)
#save_fig("top_publisher_metascore")
plt.show()
Analizzando il primo grafico si può notare come in questo caso l'aggregazione in Other dei valori di publisher meno presenti ha fatto si che tale "categoria" diventi quella con la numerosità più elevata all'interno del dataset, vedendo come nessuno dei publisher più frequenti riesca a raggiungere la soglia dei 1000 record si può supporre che dei 1923 valori differenti di publisher, i record associati ad ognuno di essi siano in numero limitato. Non vi è perciò un gruppo di "case editrici" di videogames che si distingue rispetto alle altre per numero di giochi prodotti. Inoltre dal secondo grafico si può osservare come i publisher "Blizzard Entertainment" e "Rockstar Games" si discostano dagli altri essendo gli unici i cui titoli mediamente riescano a superare la valutazione di 80 per il metascore, questo però per quanto osservato precedentemente può essere dipeso anche dalla numerosità dei loro record.
Passiamo ora alla visualizzazione degli attributi numerici (escluso year) di cui è costituito il dataset mediante l'utilizzo di Pairplot e concentrandoci principalmente sull'attributo metascore
columns=['critic_positive','critic_neutral','critic_negative','metascore','user_positive','user_neutral','user_negative','user_score']
plt.figure(figsize=(15,10))
sns.pairplot(game[columns],diag_kind="kde")
#save_fig("pairplot")
plt.show()
Analizzando la colonna di grafici relativa al metascore si può vedere una tendenza a valori più elevati in corrispondenza di elevati valori di user_score e critic_positive, maggiormente marcata per quest'ultimo attributo, mentre per quanto riguarda critic_negative si osserva il comportamento opposto ossia record con una valutazione di metascore inferiore tendono ad avere anche il maggior numero di recensioni negative da parte della critica. Indaghiamo più nello specifico le relazioni che vi sono tra gli attributi appena citati.
plt.figure(figsize=(15,10))
sns.regplot( x = "user_score", y = "metascore" ,data=game)
plt.xlabel("user score")
plt.ylabel("metascore")
plt.title("plotting (user_score, metascore)", size =20)
#save_fig("userscore_metascore")
plt.show()
plt.figure(figsize=(20,10))
p = sns.jointplot(x = 'user_score', y = 'metascore',kind='hex', data = game)
plt.title("relation between metascore and user_score", size =15)
#save_fig("userscore_metascore_jointplot")
plt.show()
Dai grafici soprastanti si può vedere come la distribuzione dei valori di metascore e user_score sono relativamente simili, inoltre i record con valutazione da parte degli utenti maggiore tendono anche ad ottenere un' elevata valutazione da parte della critica.
plt.figure(figsize=(15,10))
sns.regplot( x = "critic_negative", y = "metascore" ,data=game,color='g')
plt.xlabel("critic_negative")
plt.ylabel("metascore")
plt.title("plotting (critic_negative, metascore)", size =20)
#save_fig("criticnegative_metascore")
plt.show()
plt.figure(figsize=(20,10))
p = sns.jointplot(x = 'critic_negative', y = 'metascore', data = game,color='g',kind='hex')
plt.title("relation between critic_negative and metascore", size =15)
#save_fig("criticnegative_metascore_jointplot")
plt.show()
plt.figure(figsize=(15,10))
p = sns.kdeplot(game['critic_negative'], shade=True, color='green')
plt.grid()
plt.xlabel('Number of Negative Reviews from Critics')
plt.ylabel('Frequency')
plt.title("Critic Negative Distribution", size=20)
#save_fig("critic_negative_dist")
plt.show()
Per quanto riguarda l'attributo critic_negative si può vedere come la tendenza dei videogiochi con poche recensioni negative è quella ad avere un valore di metascore abbastanza elevato, anche se si nota come la frequenza maggiore la hanno i record con un numero di recensioni negative da parte della critica comprese tra 1 e 5.
plt.figure(figsize=(15,10))
sns.regplot( x = "critic_positive", y = "metascore" , data=game, color='c')
plt.xlabel("critic_positive")
plt.ylabel("metascore")
plt.title("plotting (critic_positive, metascore)", size =20)
#save_fig("criticpositive_metascore")
plt.show()
plt.figure(figsize=(20,10))
p = sns.jointplot(x = 'critic_positive', y = 'metascore', data = game,color='c',kind='hex')
plt.title("relation between critic_positive and metascore", size =15)
#save_fig("criticpositive_metascore_jointplot")
plt.show()
plt.figure(figsize=(15,10))
p = sns.kdeplot(game['critic_positive'], shade=True, color='c')
plt.grid()
plt.xlabel('Number of Positive Reviews from Critics')
plt.ylabel('Frequency')
plt.title("Critic Positive Distribution", size=20)
#save_fig("critic_positive_dist")
plt.show()
Inoltre, come ci si poteva aspettare, per i videogiochi che ottengono un numero elevato di recensioni positive da parte della critica si osserva anche un valore di metascore con buona probabilità elevato e superiore a 60. Si nota, similmente all'attributo precedentemente trattato, che anche per critic_positive la distribuzione dei valori si concentra maggiormente tra 0 e 10.
Si va ora a mostrare la matrice di correlazione calcolata su tali attributi numerici per indagare la presenza di eventuali correlazioni lineari positive o negative facendo ovviamente particolare attenzione all'attributo metascore.
fig,ax = plt.subplots(figsize=(15,10))
fig = sns.heatmap(game.corr(), annot=True)
plt.title("Correlations Matrix", size=20)
#save_fig("corr_matrix")
plt.show()
Effettivamente si può notare come il coefficiente di Pearson calcolato tra metascore-user_score e tra metascore-critic_positive restituisca valori superiori a 0.50 e quindi ci indica una bassa, seppur presente, correlazione positiva tra tali attributi, mentre considerando la coppia metascore-critic_negative si ottiene un valore pari a circa -0.65 che quindi sottintende alla presenza di correlazione negativa tra i due attributi. I restanti attributi non sembrano sottolineare la presenza di alcuna tipologia di correlazione lineare con metascore.
Si procede ora alla generazione di un dataframe che contenga come colonne le somme delle recensioni positive, neutrali e negative effettuate da utenti e critici per indagare se, eventuali attributi aggiuntivi non presenti nel dataset originale possano portare a scoprire relazioni incognite con l'attributo metascore.
columns_sum = ps.DataFrame({'positive_rec':game['critic_positive']+game['user_positive'],
'neutral_rec':game['critic_neutral']+game['user_neutral'],
'negative_rec':game['critic_negative']+game['user_negative'],
'metascore':game['metascore']})
columns_sum.head(10)
Una volta ottenuto per costruzione tale dataframe si procede a graficare la matrice di correlazione per questi nuovi attributi.
fig,ax = plt.subplots(figsize=(15,10))
fig = sns.heatmap(columns_sum.corr(), annot=True)
plt.title("Correlations Matrix: new columns", size=20)
plt.show()
La strada percorsa non porta un miglioramente nel calcolo del coefficiente di Pearson, anzi i valori tendono ad essere inferiori. Perciò si decide di non impiegare tali colonne nel proseguo dell'analisi.
Si termina la fase di Visualizzazione andando ad applicare sulle colonne del dataset un oggetto LabelEncoder per poter impiegare un RandomForestRegressor al fine di visualizzare quali attributi hanno una maggiore influenza nella previsione del metascore di un videogame; si può notare dal grafico sottostante come critic_positive, critic_negative e critic_neutral siano centrali per l'ottenimento del valore di metascore.
from sklearn.preprocessing import LabelEncoder
from sklearn.ensemble import RandomForestRegressor
Encoder = LabelEncoder()
data_enc = game.copy()
for c in data_enc.columns:
data_enc[c] = Encoder.fit_transform(data_enc[c])
x = data_enc.drop('metascore', axis = 1)
y = data_enc['metascore']
rfr = RandomForestRegressor(n_estimators=40, n_jobs=-1, random_state=40)
rfr.fit(x, y)
attributes = x.columns
importances = rfr.feature_importances_
index = np.argsort(importances)
plt.figure(figsize=(15,10))
plt.title("Attribute importance for the estimation of metascore",size=15)
p = plt.barh(range(len(index)), importances[index], color='g', align='center')
plt.yticks(range(len(index)), attributes[index])
plt.xlabel("Relative importance")
plt.show()
# save_fig("Attribute importance")
In questa fase, siccome le operazioni di data cleaning dei dati per l'eliminazione di eventuali valori nulli sono state effettuate a monte, si andranno ad impiegare oggetti Transformers facenti parte della libreria sklearn.preprocessing per effuettuare appunto le dovute trasformazioni degli attributi del dataset, principalmente per favorire una migliore applicazione degli algoritmi di machine learning che si andranno ad utilizzare nelle fasi successive del progetto. Come prima cosa andiamo ad escludere dal dataset la colonna relativa a metascore dalle restanti.
game_tr = game.copy()
ydf = game_tr.loc[:,['metascore']]
game_tr.drop(columns=['metascore'], inplace = True)
xdf = game_tr
xdf.head(5)
ydf.head(5)
Procediamo ora nella gestione di ogni singola colonna andando ad analizzare le trasformazioni che si applicheranno sui dati.
Per tali attributi si procede con la loro standardizzazione tramite l'applicazione di uno StandardScaler, questo perchè essendo gli attributi con la maggiore rilevanza per la stima del metascore, impiegando tale strategia di scaling si andrà ad ottenere una distribuzione di valori simile alla Normale Gaussiana (centrata intorno alla media), in modo da favorire maggiormente l'applicazione futura degli algoritmi di machine learning.
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
critics_uscore_reviews = ['critic_positive','critic_neutral','critic_negative','user_score']
std_scaler = StandardScaler()
pipe_critics_uscore = Pipeline([
('std_scaler', std_scaler)
])
Per quanto riguarda gli attributi relativi alle recensioni rilasciate dagli utenti si possono notare dei valori massimi abbastanza elevati per tali colonne, così come è elevata anche la loro deviazione standard.
users_reviews = ['user_positive','user_neutral','user_negative']
game[users_reviews].describe()
La scelta della stategia di standardizzazione per tali valori è ricaduta sull'impiego di un RobustScaler, si vanno perciò a centrare tali valori attorno alla mediana, e potenzialmente si andrà ad ottenere un risultato migliore dall'applicazione degli estimators perchè tale scaler è appunto robusto rispetto alla presenza di eventuali outliers.
from sklearn.preprocessing import RobustScaler
rbst_scaler = RobustScaler()
pipe_users = Pipeline([
('rbst_scaler', rbst_scaler)
])
La colonna in questione verrà come prima cosa discretizzata in intervalli con un numero di elementi uniformi, siccome abbiamo visto nella fase precedente che non è molto influente nella decisione del metascore e quanti pochi record siano presenti nel range di anni 1995-2000; si andranno inoltre a codificare tali intervalli seguendo una strategia di One Hot Encoding. Tutto questo può essere svolto tramite l'utilizzo di un KBinsDiscretizer.
from sklearn.preprocessing import KBinsDiscretizer
discr_year = KBinsDiscretizer(n_bins=5, encode='onehot',strategy = 'uniform')
pipe_year = Pipeline([
('discr_year', discr_year)
])
Per l'attributo rating si procede all'applicazione di encoding tramite OneHotEncoder.
from sklearn.preprocessing import OneHotEncoder
rating_enc = OneHotEncoder(sparse=False)
pipe_rating = Pipeline([
('rating_enc', rating_enc)
])
Si procede all'aggregazione dei valori di tali colonne mantenendo per genre(s) i 10 più presenti insieme ad "Other", per poi procedere all'encoding di entrambe tramite OneHotEncoder.
most_n_genre = take_most_n(10,xdf['genre(s)'])
change_value_to_other(xdf['genre(s)'],most_n_genre,inplace=True)
xdf['genre(s)'].unique()
genres_plat_col = ['genre(s)','platform']
genres_plat_enc = OneHotEncoder(sparse=False)
pipe_genres_plat = Pipeline([
('genres_plat_enc', genres_plat_enc)
])
Data la varietà di valori presente in tale colonna, non si riesce ad ottenere un valido metodo di aggregazione, nonostante ciò la loro numerosità non è così elevata da creare problemi sulla dimensionalità del dataset, perciò si procede anche in questo caso all'applicazione di encoding tramite OneHotEncoder.
players_enc = OneHotEncoder(sparse=False)
pipe_players = Pipeline([
('players_enc', players_enc)
])
Data l'elevata numerosità di valori presenti in tali attributi, una trasformazione basata su one hot encoding risulterebbe nell'inserimento di moltissime nuove colonne con valori assunti 0 o 1, questo potrebbe causare problemi nell'applicazione di algoritmi di machine learning per via dell'elevata dimensionalità del dataset. La scelta perciò è ricaduta su una strategia di encoding basata su OrdinalEncoder.
print("Numero di valori assunti dalla colonna 'developer': ",len(list(game['developer'].unique())))
print("Numero di valori assunti dalla colonna 'publisher': ",len(list(game['publisher'].unique())))
print("Numero di valori totali assunti dalle due colonne: ",len(list(game['publisher'].unique()))+len(list(game['developer'].unique())))
from sklearn.preprocessing import OrdinalEncoder
dev_publ_col = ['developer', 'publisher']
ordinal_enc = OrdinalEncoder()
pipe_dev_publ = Pipeline([
('dev_publ_enc', ordinal_enc)
])
Si procede ora con l'applicazione di tutte le Pipeline definite sul dataset mediante l'utilizzo di un oggetto ColumnTransformer.
from sklearn.compose import ColumnTransformer
full_pipeline = ColumnTransformer([
('pipe_critics_uscore', pipe_critics_uscore, critics_uscore_reviews),
('pipe_users', pipe_users, users_reviews),
('pipe_year', pipe_year, ['year']),
('pipe_rating', pipe_rating, ['rating']),
('pipe_genres_plat', pipe_genres_plat, genres_plat_col),
('pipe_players', pipe_players, ['players']),
('pipe_dev_publ', pipe_dev_publ, dev_publ_col)
])
X, Y = full_pipeline.fit_transform(xdf), ydf.values.reshape(-1)
print(X)
print(hrule(40))
print(Y)
Una volta terminata la fase di trasformazione del dataset, preceduta a monte da operazioni di datacleaning e conversione dei dati, si può procedere all'addestramento degli algoritmi di machine learning per risolvere il problema di previsione del valore di metascore per un dato videogame, come prima cosa si impiegano gli strumenti forniti dalla libreria sklearn per l'ottenimento di un test_set e di un train_set a partire dal dataset completo; avendo applicato le operazioni di trasformazione a tutti i record abbiamo il test_set già pronto per l'applicazione dei futuri modelli di previsione addestrati. Inoltre si sceglie l'utilizzo delle metriche di valutazione dei modelli: 'root mean squared error'(errore quadratico medio), 'mean absolute error' (errore medio assoluto), 'r2', 'explained variance'.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,Y, test_size=0.2)
print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV
import pickle
#metriche impiegate: root mean squared error, mean absolute error, r2, explained variance
metriche = ['neg_mean_squared_error', 'neg_mean_absolute_error', 'r2', 'explained_variance']
#metodo che passandogli un modello calcola le metriche in questione tramite l'impiego di cv e restituisce i valori
#come dataframe
ps.options.display.float_format = '{:.8f}'.format
def calcola_metriche(modello, nome, X, y):
elem = ps.DataFrame(index={0},columns=['nome','rmse', 'mae', 'r2', 'exp_var'])
elem['nome']=nome
for i in metriche:
if(i=='neg_mean_squared_error'):
score = cross_val_score(modello, X ,y, cv=10 , n_jobs=-1, scoring='neg_mean_squared_error').mean()
elem['rmse'] = np.sqrt(-score)
if(i=='neg_mean_absolute_error'):
score = cross_val_score(modello, X ,y, cv=10 , n_jobs=-1, scoring='neg_mean_absolute_error').mean()
elem['mae'] = -score
if(i=='r2'):
score = cross_val_score(modello, X ,y, cv=10 , n_jobs=-1, scoring='r2').mean()
elem['r2'] = score
if(i=='explained_variance'):
score = cross_val_score(modello, X ,y, cv=10 , n_jobs=-1, scoring='explained_variance').mean()
elem['exp_var'] = score
return elem
MODELS_PATH = os.path.join(PROJECT_ROOT_DIR, "models")
RESULTS_PATH = os.path.join(PROJECT_ROOT_DIR, "results")
modelli = []
nomi = []
risultati = ps.DataFrame()
modelli_lineari = []
nomi_modelli_lineari = []
Linear Regressor:
from sklearn.linear_model import LinearRegression
#lr = LinearRegression()
#lr.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "linear_regressor.sav")
#pickle.dump(lr, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "linear_regressor.sav")
lr = pickle.load(open(filename, 'rb'))
print(lr)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(lr, 'Linear Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "linear_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "linear_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(lr)
modelli_lineari.append(lr)
nomi.append("Linear Regressor")
nomi_modelli_lineari.append("Linear Regressor")
Ridge Regressor:
from sklearn.linear_model import Ridge
#ridge = Ridge()
#ridge.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "ridge_regressor.sav")
#pickle.dump(ridge, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "ridge_regressor.sav")
ridge = pickle.load(open(filename, 'rb'))
print(ridge)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(ridge, 'Ridge Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "ridge_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "ridge_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(ridge)
modelli_lineari.append(ridge)
nomi.append("Ridge Regressor")
nomi_modelli_lineari.append("Ridge Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params={
# 'alpha': [25,10,4,2,1.0,0.8,0.5,0.3,0.2,0.1]
#}
#ridge_grid_search = GridSearchCV(ridge, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1)
#ridge_grid_search.fit(X_train, y_train)
#best_ridge = ridge_grid_search.best_estimator_
#best_ridge
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "ridge_regressor_tuned.sav")
#pickle.dump(best_ridge, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "ridge_regressor_tuned.sav")
best_ridge = pickle.load(open(filename, 'rb'))
print(best_ridge)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_ridge, 'Ridge Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "ridge_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "ridge_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_ridge)
modelli_lineari.append(best_ridge)
nomi.append("Ridge Regressor Tuned")
nomi_modelli_lineari.append("Ridge Regressor Tuned")
Stochastic Gradient Descent Regressor:
from sklearn.linear_model import SGDRegressor
#sgd_reg = SGDRegressor(random_state=42)
#sgd_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "sgd_regressor.sav")
#pickle.dump(sgd_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "sgd_regressor.sav")
sgd_reg = pickle.load(open(filename, 'rb'))
print(sgd_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(sgd_reg, 'SGD Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "sgd_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "sgd_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(sgd_reg)
modelli_lineari.append(sgd_reg)
nomi.append("SGD Regressor")
nomi_modelli_lineari.append("SGD Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'loss': ['squared_loss', 'huber', 'epsilon_insensitive', 'squared_epsilon_insensitive'],
# 'penalty': ['l2','elasticnet', 'l1'],
# 'alpha' : [0.0001, 0.0002, 0.001, 0.005, 0.02, 0.1, 0.2],
# 'shuffle' : [True, False]
#}
#sgd_grid_search = GridSearchCV(sgd_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1)
#sgd_grid_search.fit(X_train, y_train)
#best_sgd = sgd_grid_search.best_estimator_
#best_sgd
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "sgd_regressor_tuned.sav")
#pickle.dump(best_sgd, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "sgd_regressor_tuned.sav")
best_sgd = pickle.load(open(filename, 'rb'))
print(best_sgd)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_sgd, 'SGD Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "sgd_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "sgd_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_sgd)
modelli_lineari.append(best_sgd)
nomi.append("SGD Regressor Tuned")
nomi_modelli_lineari.append("SGD Regressor Tuned")
ElasticNet Regressor:
from sklearn.linear_model import ElasticNet
#eln_reg = ElasticNet(random_state=42)
#eln_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "eln_regressor.sav")
#pickle.dump(eln_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "eln_regressor.sav")
eln_reg = pickle.load(open(filename, 'rb'))
print(eln_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(eln_reg, 'ElasticNet Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "eln_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "eln_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(eln_reg)
modelli_lineari.append(eln_reg)
nomi.append("ElasticNet Regressor")
nomi_modelli_lineari.append("ElasticNet Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'l1_ratio': [0, 0.2, 0.5, 0.7, 1],
# 'alpha': [25,10,4,2,1.0,0.8,0.5,0.3,0.2,0.1],
# 'positive' : [True, False],
# 'selection' : ['cyclic', 'random']
#}
#eln_grid_search = GridSearchCV(eln_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1)
#eln_grid_search.fit(X_train, y_train)
#best_eln = eln_grid_search.best_estimator_
#best_eln
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "eln_regressor_tuned.sav")
#pickle.dump(best_eln, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "eln_regressor_tuned.sav")
best_eln = pickle.load(open(filename, 'rb'))
print(best_eln)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_eln, 'ElasticNet Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "eln_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "eln_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_eln)
modelli_lineari.append(best_eln)
nomi.append("ElasticNet Regressor Tuned")
nomi_modelli_lineari.append("ElasticNet Regressor Tuned")
Least Angle Regression (Lars):
from sklearn.linear_model import Lars
#lars_reg = Lars()
#lars_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "lars_regressor.sav")
#pickle.dump(lars_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "lars_regressor.sav")
lars_reg = pickle.load(open(filename, 'rb'))
print(lars_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(lars_reg, 'Lars Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "lars_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "lars_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(lars_reg)
modelli_lineari.append(lars_reg)
nomi.append("Lars Regressor")
nomi_modelli_lineari.append("Lars Regressor")
Lasso Regressor:
from sklearn.linear_model import Lasso
#lasso_reg = Lasso()
#lasso_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "lasso_regressor.sav")
#pickle.dump(lasso_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "lasso_regressor.sav")
lasso_reg = pickle.load(open(filename, 'rb'))
print(lasso_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(lasso_reg, 'Lasso Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "lasso_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "lasso_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(lasso_reg)
modelli_lineari.append(lasso_reg)
nomi.append("Lasso Regressor")
nomi_modelli_lineari.append("Lasso Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'normalize': [True, False],
# 'alpha': [25,10,4,2,1.0,0.8,0.5,0.3,0.2,0],
# 'positive' : [True, False],
# 'precompute': ['auto', False],
# 'selection' : ['cyclic', 'random']
#}
#lasso_grid_search = GridSearchCV(lasso_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1)
#lasso_grid_search.fit(X_train, y_train)
#best_lasso = lasso_grid_search.best_estimator_
#best_lasso
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "lasso_regressor_tuned.sav")
#pickle.dump(best_lasso, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "lasso_regressor_tuned.sav")
best_lasso = pickle.load(open(filename, 'rb'))
print(best_lasso)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_lasso, 'Lasso Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "lasso_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "lasso_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_lasso)
modelli_lineari.append(best_lasso)
nomi.append("Lasso Regressor Tuned")
nomi_modelli_lineari.append("Lasso Regressor Tuned")
Bayesian Regressor:
from sklearn.linear_model import BayesianRidge
#bayesian_reg = BayesianRidge()
#bayesian_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "bayesian_regressor.sav")
#pickle.dump(bayesian_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "bayesian_regressor.sav")
bayesian_reg = pickle.load(open(filename, 'rb'))
print(bayesian_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(bayesian_reg, 'Bayesian Ridge Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "bayesian_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "bayesian_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(bayesian_reg)
modelli_lineari.append(bayesian_reg)
nomi.append("Bayesian Ridge Regressor")
nomi_modelli_lineari.append("Bayesian Ridge Regressor")
modelli_ib = []
nomi_modelli_ib = []
K Neighbors Regressor:
from sklearn.neighbors import KNeighborsRegressor
#knn_reg = KNeighborsRegressor()
#knn_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "knn_regressor.sav")
#pickle.dump(knn_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "knn_regressor.sav")
knn_reg = pickle.load(open(filename, 'rb'))
print(knn_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(knn_reg, 'KNeighbors Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "knn_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "knn_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(knn_reg)
modelli_ib.append(knn_reg)
nomi.append("KNeighbors Regressor")
nomi_modelli_ib.append("KNeighbors Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'n_neighbors': [3,5,7,10,15,20,50],
# 'weights': ['uniform','distance'],
# 'p': [1,2],
# 'leaf_size': [20,30,50]
#}
#knn_grid_search = GridSearchCV(knn_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1)
#knn_grid_search.fit(X_train, y_train)
#best_knn = knn_grid_search.best_estimator_
#best_knn
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "knn_regressor_tuned.sav")
#pickle.dump(best_knn, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "knn_regressor_tuned.sav")
best_knn = pickle.load(open(filename, 'rb'))
print(best_knn)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_knn, 'KNeighbors Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "knn_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "knn_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_knn)
modelli_ib.append(best_knn)
nomi.append("KNeighbors Regressor Tuned")
nomi_modelli_ib.append("KNeighbors Regressor Tuned")
Radius Neighbors Regressor:
from sklearn.neighbors import RadiusNeighborsRegressor
#rn_reg = RadiusNeighborsRegressor()
#rn_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "rn_regressor.sav")
#pickle.dump(rn_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "rn_regressor.sav")
rn_reg = pickle.load(open(filename, 'rb'))
print(rn_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(rn_reg, 'RadiusNeighbors Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "rn_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "rn_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(rn_reg)
modelli_ib.append(rn_reg)
nomi.append("RadiusNeighbors Regressor")
nomi_modelli_ib.append("RadiusNeighbors Regressor")
modelli_svm = []
nomi_modelli_svm = []
Linear Support Vector Regression:
from sklearn.svm import LinearSVR
#lsvr_reg = LinearSVR(random_state=42)
#lsvr_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "lsvr_regressor.sav")
#pickle.dump(lsvr_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "lsvr_regressor.sav")
lsvr_reg = pickle.load(open(filename, 'rb'))
print(lsvr_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(lsvr_reg, 'LinearSVR Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "lsvr_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "lsvr_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(lsvr_reg)
modelli_svm.append(lsvr_reg)
nomi.append("LinearSVR Regressor")
nomi_modelli_svm.append("LinearSVR Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'loss': ['epsilon_insensitive', 'squared_epsilon_insensitive'],
# 'C': [0.1,0.5,1.0,1.5,2,3],
# 'tol': [0.0001,0.0002,0.001,0.002,0.01]
#}
#lsvr_grid_search = GridSearchCV(lsvr_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1)
#lsvr_grid_search.fit(X_train, y_train)
#best_lsvr = lsvr_grid_search.best_estimator_
#best_lsvr
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "lsvr_regressor_tuned.sav")
#pickle.dump(best_lsvr, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "lsvr_regressor_tuned.sav")
best_lsvr = pickle.load(open(filename, 'rb'))
print(best_lsvr)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_lsvr, 'LinearSVR Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "lsvr_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "lsvr_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_lsvr)
modelli_svm.append(best_lsvr)
nomi.append("LinearSVR Regressor Tuned")
nomi_modelli_svm.append("LinearSVR Regressor Tuned")
Support Vector Regression:
from sklearn.svm import SVR
#svr_reg = SVR()
#svr_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "svr_regressor.sav")
#pickle.dump(svr_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "svr_regressor.sav")
svr_reg = pickle.load(open(filename, 'rb'))
print(svr_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(svr_reg, 'SVR Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "svr_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "svr_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(svr_reg)
modelli_svm.append(svr_reg)
nomi.append("SVR Regressor")
nomi_modelli_svm.append("SVR Regressor")
modelli_ann = []
nomi_modelli_ann = []
Multi-layer Perceptron regressor:
from sklearn.neural_network import MLPRegressor
#mlpr_reg = MLPRegressor()
#mlpr_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "mlpr_regressor.sav")
#pickle.dump(mlpr_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "mlpr_regressor.sav")
mlpr_reg = pickle.load(open(filename, 'rb'))
print(mlpr_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(mlpr_reg, 'Multi-layer Perceptron Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "mlpr_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "mlpr_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(mlpr_reg)
modelli_ann.append(mlpr_reg)
nomi.append("Multi-layer Perceptron Regressor")
nomi_modelli_ann.append("Multi-layer Perceptron Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'activation': ['relu', 'tanh', 'logistic'],
# 'solver': ['adam', 'lbfgs'],
# 'hidden_layer_sizes': [10,25,50,100,150],
# 'learning_rate' : ['constant', 'adaptive'],
# 'max_iter' : [500]
#}
#mlpr_grid_search = GridSearchCV(mlpr_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1, verbose = 3)
#mlpr_grid_search.fit(X_train, y_train)
#best_mlpr = mlpr_grid_search.best_estimator_
#best_mlpr
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "mlpr_regressor_tuned.sav")
#pickle.dump(best_mlpr, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "mlpr_regressor_tuned.sav")
best_mlpr = pickle.load(open(filename, 'rb'))
print(best_mlpr)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_mlpr, 'Multi-layer Perceptron Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "mlpr_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "mlpr_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_mlpr)
modelli_ann.append(best_mlpr)
nomi.append("Multi-layer Perceptron Regressor Tuned")
nomi_modelli_ann.append("Multi-layer Perceptron Regressor Tuned")
modelli_tree = []
nomi_modelli_tree = []
Decision Tree Regressor:
from sklearn.tree import DecisionTreeRegressor
#dtree_reg = DecisionTreeRegressor(random_state=42)
#dtree_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "dtree_regressor.sav")
#pickle.dump(dtree_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "dtree_regressor.sav")
dtree_reg = pickle.load(open(filename, 'rb'))
print(dtree_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(dtree_reg, 'Decision Tree Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "dtree_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "dtree_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(dtree_reg)
modelli_tree.append(dtree_reg)
nomi.append("Decision Tree Regressor")
nomi_modelli_tree.append("Decision Tree Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'criterion': ['mse', 'friedman_mse', 'mae'],
# 'splitter': ['best', 'random'],
# 'max_features' : ['auto', 'sqrt', None]
#}
#dtree_grid_search = GridSearchCV(dtree_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1, verbose = 3)
#dtree_grid_search.fit(X_train, y_train)
#best_dtree = dtree_grid_search.best_estimator_
#best_dtree
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "dtree_regressor_tuned.sav")
#pickle.dump(best_dtree, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "dtree_regressor_tuned.sav")
best_dtree = pickle.load(open(filename, 'rb'))
print(best_dtree)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_dtree, 'Decision Tree Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "dtree_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "dtree_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_dtree)
modelli_tree.append(best_dtree)
nomi.append("Decision Tree Regressor Tuned")
nomi_modelli_tree.append("Decision Tree Regressor Tuned")
Extra Tree Regressor:
from sklearn.tree import ExtraTreeRegressor
#etree_reg = ExtraTreeRegressor(random_state=42)
#etree_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "etree_regressor.sav")
#pickle.dump(etree_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "etree_regressor.sav")
etree_reg = pickle.load(open(filename, 'rb'))
print(etree_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(etree_reg, 'Extra Tree Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "etree_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "etree_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(etree_reg)
modelli_tree.append(etree_reg)
nomi.append("Extra Tree Regressor")
nomi_modelli_tree.append("Extra Tree Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'criterion': ['mse', 'friedman_mse', 'mae'],
# 'splitter': ['best', 'random'],
# 'max_features' : ['auto', 'sqrt', None, 'log2',1]
#}
#etree_grid_search = GridSearchCV(etree_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1, verbose = 3)
#etree_grid_search.fit(X_train, y_train)
#best_etree = etree_grid_search.best_estimator_
#best_etree
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "etree_regressor_tuned.sav")
#pickle.dump(best_etree, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "etree_regressor_tuned.sav")
best_etree = pickle.load(open(filename, 'rb'))
print(best_etree)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_etree, 'Extra Tree Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "etree_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "etree_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_etree)
modelli_tree.append(best_etree)
nomi.append("Extra Tree Regressor Tuned")
nomi_modelli_tree.append("Extra Tree Regressor Tuned")
modelli_ensemble = []
nomi_modelli_ensemble = []
Random Forest Regressor:
from sklearn.ensemble import RandomForestRegressor
#rndf_reg = RandomForestRegressor(random_state=42)
#rndf_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "rndf_regressor.sav")
#pickle.dump(rndf_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "rndf_regressor.sav")
rndf_reg = pickle.load(open(filename, 'rb'))
print(rndf_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(rndf_reg, 'Random Forest Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "rndf_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "rndf_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(rndf_reg)
modelli_ensemble.append(rndf_reg)
nomi.append("Random Forest Regressor")
nomi_modelli_ensemble.append("Random Forest Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'n_estimators' : [10,50,70,100,150],
# 'criterion': ['mse', 'mae'],
# 'max_features' : ['auto', 'sqrt','log2', None],
# 'bootstrap' : [True, False],
# 'n_jobs' : [-1]
#}
#rndfr_grid_search = GridSearchCV(rndf_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1, verbose = 3)
#rndfr_grid_search.fit(X_train, y_train)
#best_rndfr = rndfr_grid_search.best_estimator_
#best_rndfr
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "rndf_regressor_tuned.sav")
#pickle.dump(best_rndfr, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "rndf_regressor_tuned.sav")
best_rndfr = pickle.load(open(filename, 'rb'))
print(best_rndfr)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_rndfr, 'Random Forest Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "rndf_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "rndf_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_rndfr)
modelli_ensemble.append(best_rndfr)
nomi.append("Random Forest Regressor Tuned")
nomi_modelli_ensemble.append("Random Forest Regressor Tuned")
Bagging Regressor:
from sklearn.ensemble import BaggingRegressor
#bagging_reg = BaggingRegressor(random_state=42,n_jobs=-1)
#bagging_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "bagging_regressor.sav")
#pickle.dump(bagging_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "bagging_regressor.sav")
bagging_reg = pickle.load(open(filename, 'rb'))
print(bagging_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(bagging_reg, 'Bagging Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "bagging_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "bagging_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(bagging_reg)
modelli_ensemble.append(bagging_reg)
nomi.append("Bagging Regressor")
nomi_modelli_ensemble.append("Bagging Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'n_estimators' : [10,50,70,100,150],
# 'bootstrap_features' : [True, False],
# 'bootstrap' : [True, False],
# 'max_features' : [1.0,5,10]
#}
#bagging_grid_search = GridSearchCV(bagging_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1, verbose = 3)
#bagging_grid_search.fit(X_train, y_train)
#best_bagging = bagging_grid_search.best_estimator_
#best_bagging
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "bagging_regressor_tuned.sav")
#pickle.dump(best_bagging, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "bagging_regressor_tuned.sav")
best_bagging = pickle.load(open(filename, 'rb'))
print(best_bagging)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_bagging, 'Bagging Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "bagging_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "bagging_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_bagging)
modelli_ensemble.append(best_bagging)
nomi.append("Bagging Regressor Tuned")
nomi_modelli_ensemble.append("Bagging Regressor Tuned")
AdaBoost Regressor:
from sklearn.ensemble import AdaBoostRegressor
#adab_reg = AdaBoostRegressor(base_estimator=DecisionTreeRegressor(),random_state=42)
#adab_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "adab_regressor.sav")
#pickle.dump(adab_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "adab_regressor.sav")
adab_reg = pickle.load(open(filename, 'rb'))
print(adab_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(adab_reg, 'AdaBoost Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "adab_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "adab_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(adab_reg)
modelli_ensemble.append(adab_reg)
nomi.append("AdaBoost Regressor")
nomi_modelli_ensemble.append("AdaBoost Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'n_estimators' : [10,50,70,100,150],
# 'loss' : ['linear', 'square', 'exponential'],
# 'learning_rate' : [1.0,0.5,0.7]
#}
#adab_grid_search = GridSearchCV(adab_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1, verbose = 3)
#adab_grid_search.fit(X_train, y_train)
#best_adab = adab_grid_search.best_estimator_
#best_adab
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "adab_regressor_tuned.sav")
#pickle.dump(best_adab, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "adab_regressor_tuned.sav")
best_adab = pickle.load(open(filename, 'rb'))
print(best_adab)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_adab, 'AdaBoost Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "adab_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "adab_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_adab)
modelli_ensemble.append(best_adab)
nomi.append("AdaBoost Regressor Tuned")
nomi_modelli_ensemble.append("AdaBoost Regressor Tuned")
Gradient Boosting Regressor:
from sklearn.ensemble import GradientBoostingRegressor
#gb_reg = GradientBoostingRegressor(random_state=42)
#gb_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "gb_regressor.sav")
#pickle.dump(gb_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "gb_regressor.sav")
gb_reg = pickle.load(open(filename, 'rb'))
print(gb_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(gb_reg, 'Gradient Boosting Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "gb_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "gb_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(gb_reg)
modelli_ensemble.append(gb_reg)
nomi.append("Gradient Boosting Regressor")
nomi_modelli_ensemble.append("Gradient Boosting Regressor")
Procedo ad effettuare parameter tuning per tale modello mediante l'utilizzo di Grid Search:
#params = {
# 'n_estimators' : [10,50,100,150],
# 'loss' : ['ls', 'lad', 'huber'],
# 'learning_rate' : [1.0,0.5,0.7,0.1],
# 'max_depth' : [3,5,10]
#}
#gb_grid_search = GridSearchCV(gb_reg, params, cv = 5, scoring = 'neg_mean_squared_error', n_jobs = -1, verbose = 3)
#gb_grid_search.fit(X_train, y_train)
#best_gb = gb_grid_search.best_estimator_
#best_gb
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "gb_regressor_tuned.sav")
#pickle.dump(best_gb, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "gb_regressor_tuned.sav")
best_gb = pickle.load(open(filename, 'rb'))
print(best_gb)
Si procede a verificare le prestazioni del modello tuned tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(best_gb, 'Gradient Boosting Regressor Tuned', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "gb_regressor_tuned_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "gb_regressor_tuned_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(best_gb)
modelli_ensemble.append(best_gb)
nomi.append("Gradient Boosting Regressor Tuned")
nomi_modelli_ensemble.append("Gradient Boosting Regressor Tuned")
Stacked Generalization:
Si procede nell'applicazione della tecnica definita Stacked Generalization tramite l'impiego dell'estimator StackingRegressor della libreria sklearn.ensemble.
from sklearn.ensemble import StackingRegressor
#definisco gli estimators che faranno parte del primo livello:
#estimators_list = [
# ('decision_tree', DecisionTreeRegressor(criterion='friedman_mse', max_features='auto', random_state=42)),
#('extra_tree', ExtraTreeRegressor(criterion='friedman_mse', splitter='best', random_state=42)),
# ('random_f',RandomForestRegressor(n_estimators=150,random_state=42))
#]
#definisco il final_estimator, ossia il blender che metterà assieme i risultati dei precedenti estimator, fornendo il risultato finale
#blender = GradientBoostingRegressor(loss='ls',max_depth=5,random_state=42)
#stacking_reg = StackingRegressor(estimators=estimators_list, final_estimator=blender, n_jobs=-1, passthrough=True)
#stacking_reg.fit(X_train, y_train)
#salvo il modello su disco
#filename = os.path.join(MODELS_PATH, "stacking_regressor.sav")
#pickle.dump(stacking_reg, open(filename, 'wb'))
#carico il modello dal disco
filename = os.path.join(MODELS_PATH, "stacking_regressor.sav")
stacking_reg = pickle.load(open(filename, 'rb'))
print(stacking_reg)
Si procede a verificare le prestazioni di tale modello tramite l'impiego del metodo calcola_metriche precedentemente definito:
#r = calcola_metriche(stacking_reg, 'Stacking Regressor', X_train, y_train)
#r.to_csv(os.path.join(RESULTS_PATH, "stacking_regressor_res.csv"), index = False)
r = ps.read_csv(os.path.join(RESULTS_PATH, "stacking_regressor_res.csv"), index_col='nome')
r
#Carico i risultati nel dataset che mi conterrà i risultati di tutti i modelli impiegati
risultati = risultati.append(r)
risultati.to_csv(os.path.join(RESULTS_PATH, "risultati.csv"))
risultati = ps.read_csv(os.path.join(RESULTS_PATH, "risultati.csv"), index_col='nome')
modelli.append(stacking_reg)
modelli_ensemble.append(stacking_reg)
nomi.append("Stacking Regressor")
nomi_modelli_ensemble.append("Stacking Regressor")
Come primo passo nella nostra analisi delle prestazioni dei modelli precedentemente addestrati sul training set, andiamo a mostrare i risultati ottenuti che sono stati caricati in corso d'opera appositamente in un DataFrame. Si ricorda inoltre che le metriche impiegate per la valutazione sono: root mean squared error, mean absolute error ( per entrambe valori inferiori suggeriscono un ridotto errore del modello), r2 ed explained variance (queste invece ammetteno valore massimo 1 e valori tendenti ad 1 suggeriscono la correttezza delle previsioni del modello, possono inoltre assumere valore negativo ed in questo caso avremo a che fare con modelli non corretti).
risultati
Una prima visione del DataFrame contenente i risultati ci porta a scoprire la piena scorrettezza dei regressori SGD Regressor (anche in versione tuned), Lars Regressor e Radius Neighbors Regressor che quindi costituiscono i peggiori modelli per prestazioni misurate sul training set e probabilmente suggeriscono la presenza di underfiting, dati i valori delle metriche di errore così elevati e addirittura la presenza di valori negativi nettamente sotto lo 0 per le metriche r2 ed explained variance. Si procede perciò alla rimozione delle rispettive entry nel dataframe per una più corretta analisi nel proseguo.
bad_estimators = ["SGD Regressor", "SGD Regressor Tuned", "Lars Regressor", "RadiusNeighbors Regressor"]
risultati = risultati.drop(bad_estimators)
#procedo alla rimozione di tali modelli anche dalle liste in cui sono stati conservati nel corso della sezione precedente
modelli.remove(sgd_reg)
modelli.remove(best_sgd)
modelli.remove(lars_reg)
modelli_lineari.remove(sgd_reg)
modelli_lineari.remove(best_sgd)
modelli_lineari.remove(lars_reg)
nomi.remove("SGD Regressor")
nomi.remove("SGD Regressor Tuned")
nomi.remove("Lars Regressor")
nomi_modelli_lineari.remove("SGD Regressor")
nomi_modelli_lineari.remove("SGD Regressor Tuned")
nomi_modelli_lineari.remove("Lars Regressor")
modelli.remove(rn_reg)
modelli_ib.remove(rn_reg)
nomi.remove("RadiusNeighbors Regressor")
nomi_modelli_ib.remove("RadiusNeighbors Regressor")
risultati
Prima di procedere alla visualizzazione ed analisi dei risultati andiamo a mantenere, ove possibile, unicamente le righe che fanno riferimento a modelli per cui è stato effettuato parameter tuning, perchè rispetto ai modelli di default hanno prestazioni migliori ( ad eccezione del Linear SVR Regressor per cui si notano risultati migliori nella forma di base).
#Rimozione Ridge Regressor
modelli.remove(ridge)
modelli_lineari.remove(ridge)
nomi.remove("Ridge Regressor")
nomi_modelli_lineari.remove("Ridge Regressor")
#Rimozione ElasticNet Regressor
modelli.remove(eln_reg)
modelli_lineari.remove(eln_reg)
nomi.remove("ElasticNet Regressor")
nomi_modelli_lineari.remove("ElasticNet Regressor")
#Rimozione Lasso Regressor
modelli.remove(lasso_reg)
modelli_lineari.remove(lasso_reg)
nomi.remove("Lasso Regressor")
nomi_modelli_lineari.remove("Lasso Regressor")
#Rimozione KNeighbors Regressor
modelli.remove(knn_reg)
modelli_ib.remove(knn_reg)
nomi.remove("KNeighbors Regressor")
nomi_modelli_ib.remove("KNeighbors Regressor")
#Rimozione LinearSVR Regressor Tuned
modelli.remove(best_lsvr)
modelli_svm.remove(best_lsvr)
nomi.remove("LinearSVR Regressor Tuned")
nomi_modelli_svm.remove("LinearSVR Regressor Tuned")
#Rimozione Multi-layer Perceptron Regressor
modelli.remove(mlpr_reg)
modelli_ann.remove(mlpr_reg)
nomi.remove("Multi-layer Perceptron Regressor")
nomi_modelli_ann.remove("Multi-layer Perceptron Regressor")
#Rimozione Decision Tree Regressor
modelli.remove(dtree_reg)
modelli_tree.remove(dtree_reg)
nomi.remove("Decision Tree Regressor")
nomi_modelli_tree.remove("Decision Tree Regressor")
#Rimozione Extra Tree Regressor
modelli.remove(etree_reg)
modelli_tree.remove(etree_reg)
nomi.remove("Extra Tree Regressor")
nomi_modelli_tree.remove("Extra Tree Regressor")
#Rimozione Random Forest Regressor
modelli.remove(rndf_reg)
modelli_ensemble.remove(rndf_reg)
nomi.remove("Random Forest Regressor")
nomi_modelli_ensemble.remove("Random Forest Regressor")
#Rimozione Bagging Regressor
modelli.remove(bagging_reg)
modelli_ensemble.remove(bagging_reg)
nomi.remove("Bagging Regressor")
nomi_modelli_ensemble.remove("Bagging Regressor")
#Rimozione AdaBoost Regressor
modelli.remove(adab_reg)
modelli_ensemble.remove(adab_reg)
nomi.remove("AdaBoost Regressor")
nomi_modelli_ensemble.remove("AdaBoost Regressor")
#Rimozione Gradient Boosting Regressor
modelli.remove(gb_reg)
modelli_ensemble.remove(gb_reg)
nomi.remove("Gradient Boosting Regressor")
nomi_modelli_ensemble.remove("Gradient Boosting Regressor")
#seleziono i risultati da mostrare una volta terminata la rimozione di cui sopra
risultati=risultati.loc[nomi_modelli_lineari+nomi_modelli_ib+nomi_modelli_svm+nomi_modelli_ann+nomi_modelli_tree+nomi_modelli_ensemble]
risultati
Andiamo ora a visualizzare i valori delle rispettive metriche per ogni modello scelto da considerare:
plt.figure(figsize=(15,10))
sorted_rmse = risultati.sort_values(by = 'rmse')
sns.barplot(x = sorted_rmse.index, y = sorted_rmse.rmse)
plt.xticks(rotation=90)
plt.title("RMSE TRAIN SET", size=20)
#save_fig("RMSE TRAIN SET")
plt.show()
plt.figure(figsize=(15,10))
sorted_mae = risultati.sort_values(by = 'mae')
sns.barplot(x = sorted_mae.index, y = sorted_mae.mae)
plt.xticks(rotation=90)
plt.title("MAE TRAIN SET", size=20)
#save_fig("MAE TRAIN SET")
plt.show()
plt.figure(figsize=(15,10))
sorted_r2 = risultati.sort_values(by = 'r2')
sns.barplot(x = sorted_r2.index, y = sorted_r2.r2)
plt.xticks(rotation=90)
plt.title("R2 TRAIN SET", size=20)
#save_fig("R2 TRAIN SET")
plt.show()
plt.figure(figsize=(15,10))
sorted_var = risultati.sort_values(by = 'exp_var')
sns.barplot(x = sorted_var.index, y = sorted_var['exp_var'])
plt.xticks(rotation=90)
plt.title("EXPLAINED VARIANCE TRAIN SET", size=20)
#save_fig("EXPLAINED VARIANCE TRAIN SET")
plt.show()
Da quanto si può osservare nei grafici precedenti il peggiore modello tra tutti (tralasciando i modelli precedentemente esclusi ossia SGD, Lars e Radius Neighbors Regressor) come prestazioni sul train set, a prescindere dalla metrica considerata, risulta essere SVR Regressor, ha infatti elevati valori di root mean squared error e mean absolut error e inoltre per quando riguarda la metrica r2 si notano addirittura valori negativi. I migliori modelli sono senza dubbio quelli facenti parte della categoria di metodi ensemble, infatti il primo modello per risultati migliori è proprio il Gradient Boosting Regressor, seguito poi dal Random Forest Regressor e successivamente dagli altri modelli ensemble che sono stati impiegati nell'analisi. Buoni risultati ci vengono anche forniti dal Multi-Layer Perceptron Regressor e dai modelli ad albero quali Decision Tree Regressor e Extra Tree Regressor, anche se non sono comunque al livello dei precedenti. I peggiori modelli per prestazioni sul train set, oltre ad SVR, rientrano nella categoria dei modelli basati su Support Vector Machine e sul calcolo dei Nearest Neighbours. Infine troviamo nel mezzo la categoria dei modelli lineari con valori di metriche discreti ma comunque superiori rispetto ai modelli ad albero e basati su ANN.
Procediamo ora a consolidare quanto appreso mostrando la media dei valori delle rispettive metriche calcolate per ogni tipologia complessiva (modelli lineari, modelli instance based, ecc..) di modelli addestrati:
aggregati_res_train = ps.DataFrame(index=['Modelli Lineari','Modelli Instance Based','Modelli SVM','Modelli ANN','Modelli ad Albero','Modelli Ensemble'])
linear = risultati.loc[nomi_modelli_lineari]
instance_based = risultati.loc[nomi_modelli_ib]
support_vector = risultati.loc[nomi_modelli_svm]
ann = risultati.loc[nomi_modelli_ann]
tree = risultati.loc[nomi_modelli_tree]
ensemble = risultati.loc[nomi_modelli_ensemble]
rmse_mean = [linear.rmse.mean(),instance_based.rmse.mean(),support_vector.rmse.mean(),ann.rmse.mean(),tree.rmse.mean(),ensemble.rmse.mean()]
mae_mean = [linear.mae.mean(),instance_based.mae.mean(),support_vector.mae.mean(),ann.mae.mean(),tree.mae.mean(),ensemble.mae.mean()]
r2_mean = [linear.r2.mean(),instance_based.r2.mean(),support_vector.r2.mean(),ann.r2.mean(),tree.r2.mean(),ensemble.r2.mean()]
expvar_mean = [linear['exp_var'].mean(),instance_based['exp_var'].mean(),support_vector['exp_var'].mean(),ann['exp_var'].mean(),tree['exp_var'].mean(),ensemble['exp_var'].mean()]
aggregati_res_train['mean_rmse'] = rmse_mean
aggregati_res_train['mean_mae'] = mae_mean
aggregati_res_train['mean_r2'] = r2_mean
aggregati_res_train['mean_expvar'] = expvar_mean
aggregati_res_train
plt.figure(figsize=(15,10))
sns.barplot(x = aggregati_res_train.index, y = aggregati_res_train['mean_rmse'])
plt.title("MEDIA RMSE PER TIPO DI MODELLI TRAIN SET", size=20)
#save_fig("MEDIA RMSE TRAIN")
plt.show()
plt.figure(figsize=(15,10))
sns.barplot(x = aggregati_res_train.index, y = aggregati_res_train['mean_mae'])
plt.title("MEDIA MAE PER TIPO DI MODELLI TRAIN SET", size=20)
#save_fig("MEDIA MAE TRAIN")
plt.show()
plt.figure(figsize=(15,10))
sns.barplot(x = aggregati_res_train.index, y = aggregati_res_train['mean_r2'])
plt.title("MEDIA R2 PER TIPO DI MODELLI TRAIN SET", size=20)
#save_fig("MEDIA R2 TRAIN")
plt.show()
plt.figure(figsize=(15,10))
sns.barplot(x = aggregati_res_train.index, y = aggregati_res_train['mean_expvar'])
plt.title("MEDIA EXPLAINED VARIANCE PER TIPO DI MODELLI TRAIN SET", size=20)
#save_fig("MEDIA EXPVAR TRAIN")
plt.show()
Si può appunto sottolineare grazie ai grafici di cui sopra, come i Modelli Ensemble costituiscano la categoria di modelli che raggiungono le prestazioni migliori sul train set rispetto a tutti gli altri, seguiti dai Modelli ANN e successivamente dai Modelli ad ALbero. I peggiori, come già detto precedentemente, risultano essere i Modelli SVM (tra tutti ci restituiscono i valori delle metrice peggiori) ed i Modelli Instance Based; infine per quanto riguarda i Modelli Lineari si riscontrano errori abbastanza elevati ma comunque inferiori alle classi di modelli precedentemente trattate.
Si procede ora ad applicare i modelli precedentemente addestrati e selezionati sul test set, preparato nelle passate sezioni di tale progetto, questo è stato già trasformato a monte tramite l'utilizzo dell ColumnTransformer e perciò è necessario unicamente effettuare le prevesioni dei valori di metascore. Siccome la funzione precedentemente definita per il calcolo delle metriche sul test set impiega cross-validation, andrebbe a rifittare i modelli sul test set per la restituzione dei valori delle metriche; per questo motivo si procede alla definizione di una nuova funzione "calcola_risultati_test" che non impiega CV. Inoltre dato l'utilizzo di cross-validation per la valutazione delle performance dei modelli ci si aspettano sul test set risultati presumibilmente simili a quelli visti sul training set
from sklearn.metrics import explained_variance_score, mean_absolute_error, mean_squared_error, r2_score
import pickle
ps.options.display.float_format = '{:.8f}'.format
risultati_test = ps.DataFrame(index=nomi,columns=['rmse', 'mae', 'r2', 'exp_var'])
#metodo che passandogli la lista di modelli addestrati sul train set calcola le varie metriche
def calcola_risultati_test(modelli,nomi):
for i in range(len(modelli)):
modello = modelli[i]
y_pred = modello.predict(X_test)
nome = nomi[i]
risultati_test.loc[nome,'rmse'] = np.sqrt(mean_squared_error(y_test,y_pred))
risultati_test.loc[nome,'mae'] = mean_absolute_error(y_test,y_pred)
risultati_test.loc[nome,'r2'] = r2_score(y_test,y_pred)
risultati_test.loc[nome,'exp_var'] = explained_variance_score(y_test,y_pred)
return
#calcola_risultati_test(modelli,nomi)
#risultati_test.to_csv(os.path.join(RESULTS_PATH, "risultati_test.csv"))
risultati_test = ps.read_csv(os.path.join(RESULTS_PATH, "risultati_test.csv"), index_col=[0])
risultati_test
Una volta ottenuti i risultati delle metriche per i modelli selezionati nella sezione precedente, si può procedere alla loro visualizzazione ed analisi, a prima vista sembrerebbe che in generale si riscontrino per tutti i modelli dei valori migliori rispetto ai risultati ottenuti sul training set (questo probabilemte dovuto al fatto che precedentemente è stata impiegata cross-validation con la divisione del dataset in 10 fold al fine del calcolo delle metriche di errore).
plt.figure(figsize=(15,10))
sorted_rmse_test = risultati_test.sort_values(by = 'rmse')
sns.barplot(x = sorted_rmse_test.index, y = sorted_rmse_test.rmse)
plt.xticks(rotation=90)
plt.title("RMSE TEST SET", size=20)
#save_fig("RMSE TEST SET")
plt.show()
plt.figure(figsize=(15,10))
sorted_mae_test = risultati_test.sort_values(by = 'mae')
sns.barplot(x = sorted_mae_test.index, y = sorted_mae_test.mae)
plt.xticks(rotation=90)
plt.title("MAE TEST SET", size=20)
#save_fig("MAE TEST SET")
plt.show()
plt.figure(figsize=(15,10))
sorted_r2_test = risultati_test.sort_values(by = 'r2')
sns.barplot(x = sorted_r2_test.index, y = sorted_r2_test.r2)
plt.xticks(rotation=90)
plt.title("R2 TEST SET", size=20)
#save_fig("R2 TEST SET")
plt.show()
plt.figure(figsize=(15,10))
sorted_var_test = risultati_test.sort_values(by = 'exp_var')
sns.barplot(x = sorted_var_test.index, y = sorted_var_test['exp_var'])
plt.xticks(rotation=90)
plt.title("EXPLAINED VARIANCE TEST SET", size=20)
#save_fig("EXPLAINED VARIANCE TEST SET")
plt.show()
Come detto in precedenza, dato che l'analisi delle metriche sul training set è stata effettuata mediante l'impiego di cross-validation, i risultati ottenuti sul test set restano in linea con quanto osservato fino ad ora. I modelli basati sulle tecniche ensemble risultano essere quelli che restituiscono i risultati migliori, tra tutti il Gradient Boosting Regressor è quello che restituisce previsioni maggiormente corrette, seguito poi dal RandomForest Regressor; i peggiori risultati ci vengono invece restituiti dal SVR Regressor, mentre conservano la stessa posizione sul podio le categorie di modelli lineari, basati su ANN e basati su alberi. Di seguito si può vedere la distribuzione dei valori di metascore predetti dal Gradient Boosting Regressor sul test set mettendola a confronto con gli effettivi valori corretti contenuti in y_test; le curve risultano essere molto simili, si può notare come gli errori si concentrano maggiormente nei pressi del valore '100' di metascore e nel tratto compreso tra '65', circa, ed '80'.
gbr = modelli_ensemble[3]
y_gbr = gbr.predict(X_test)
plt.figure(figsize=(15,10))
sns.kdeplot(data=y_gbr,shade=True,label='valori predetti',color='r')
sns.kdeplot(data=y_test,shade=True,label='valori reali',color='g')
plt.title("Distribuzione valori predetti da GBR", size=20)
#save_fig("distribuzione valori predetti")
plt.show()
Si conclude perciò che mediante l'impiego dei Modelli Ensemble è possibile predire, con una stima dell'errore abbastanza bassa (inferiore al 3%), il valore di metascore per un determinato videogame.